Skip to content

ci: run the orphaned test/db regression runners (and make them portable) - #153

Merged
gburd merged 4 commits into
masterfrom
ci/wire-testdb-runners
Sep 7, 2026
Merged

ci: run the orphaned test/db regression runners (and make them portable)#153
gburd merged 4 commits into
masterfrom
ci/wire-testdb-runners

Conversation

@gburd

@gburd gburd commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

test/db/ holds four runners that each guard a specific fixed bug, but none was invoked by any CI job or build target — so a regression in the code they cover would have gone unnoticed.

Runner Guards
run_hash_unsorted_cmp the #139 hash comparator fix (PR #144)
run_recd_compact compact-path recovery
run_recd_handlers recovery handler dispatch
run_upgrade the on-disk upgrade path

How this surfaced

While double-checking that the #139 fix on master really contains both required changes. It does — LEN_HKEY(dbp, p, dbp->pgsize, i) for the stored item's length and res = t->h_compare(...) capturing the result. The second matters: with only the reported half, a prefix search key compares equal against a truncated view of the stored key, turning the false negative into a false positive (get("acct") returning acct0000's data). The test proving this is thorough — false-negative, false-positive-on-prefix, over-long key, and DB_NOOVERWRITE — but nothing ran it.

Wiring them up exposed three real portability bugs

Enabling them on the existing build matrix made all four macOS jobs fail, each time for a different reason. All three were genuine latent defects in the runners, not CI noise:

  1. Library probe was Linux-only — looked for .libs/libdb-*.so; macOS builds libdb-5.3.dylib.
  2. timeout is GNU coreutils — absent on stock macOS (rc=127). Added a run_with_timeout helper: timeoutgtimeout → run without one. Losing the timeout beats a false failure. Both branches exercised explicitly, including that the fallback drops the seconds argument.
  3. Root cause — the .dylib's baked-in install name (/usr/local/BerkeleyDB.5.3/lib/...) takes precedence over -Wl,-rpath on macOS, so the binary aborted in dyld against an uninstalled path. The runners never needed dynamic linking, so they now prefer libdb.a (what test/fuzz already does) and only fall back to shared. Also replaced hardcoded gcc with "${CC:-cc}", which would have been the next failure.

Verification

  • Locally 4/4 PASS, and ldd hash_unsorted_cmp | grep -c libdb = 0, confirming the static link.
  • On macOS: Compiling hash_unsorted_cmp against ./libdb.a then all four .sh: PASS.
  • Full matrix green; actionlint clean for the new step.

No engine changes.

test/db/ holds four runners that each guard a specific fixed bug, but NONE was
invoked by any CI job or build target, so a regression in the code they cover
would have gone unnoticed:

  run_hash_unsorted_cmp  the #139 hash comparator fix (PR #144)
  run_recd_compact       compact-path recovery
  run_recd_handlers      recovery handler dispatch
  run_upgrade            the on-disk upgrade path

Found while verifying that the #139 fix on master really contains BOTH required
changes (it does: LEN_HKEY for the stored item's length, and capturing the
comparator's result). The test proving that is thorough -- it covers the
false-negative, the false-positive-on-prefix that appears if only the reported
half is fixed, and an over-long key -- but nothing ran it.

Added to the 'default' matrix config of the existing build job, which already
builds build_unix with the shared library. All four follow the same
BUILD=${BUILD:-.} convention and run from the build directory.

Verified locally with the exact CI command sequence: 4/4 PASS. actionlint reports
no findings for the new step.
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

Coccinelle convention checks

No new violations. ✅

Resolved since baseline (2) -- update dist/cocci/baseline.txt to lock these in.
rule_mutex_unbalanced|MUTEX_UNBALANCED|src/crypto/mersenne/mt19937db.c|return (ret);
rule_mutex_unbalanced|MUTEX_UNBALANCED|src/mp/mp_register.c|return (ret);

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

ABI diff vs v5.3.34 (libabigail — authoritative)

Functions changes summary: 0 Removed, 0 Changed, 2 Added functions
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable

2 Added functions:

  [A] 'function int __lock_sireap_lockers(ENV*)'    {__lock_sireap_lockers}
  [A] 'function int __os_csprng(ENV*, void*, size_t)'    {__os_csprng}

Removed exported symbols (nm -D, _NNNN version suffix normalized)

None.


Advisory: libabigail/nm is the authoritative binary-ABI check; Coccinelle is complementary source-level early warning. See dist/cocci/README.md.

Wiring these runners into CI (previous commit) exposed a real portability gap:
the library probe looked only for .libs/libdb-*.so, so all four macOS jobs failed
with 'libdb .so not found'. macOS builds libdb-5.3.dylib.

The probe now tries the exact .so and .dylib names first, then the globs for
each, and its failure message names both suffixes. The -Wl,-rpath linking already
works on both platforms, so nothing else needed changing.

Verified: 4/4 PASS on Linux (unchanged), and the new probe resolves a
.dylib-only build directory.
Second macOS gap exposed by wiring these runners into CI. The .dylib probe fixed
the library lookup, and the runners then compiled and linked fine on macOS, but
all four still failed with rc=127: 'timeout: command not found'. GNU coreutils'
timeout is not on stock macOS, where it is gtimeout if coreutils is installed.

Added a run_with_timeout helper to each runner: prefer timeout, then gtimeout,
and if neither exists run the command WITHOUT a timeout rather than failing --
losing the timeout is much better than reporting a false failure.

Both branches were exercised explicitly, including that the no-timeout path drops
the leading seconds argument. 4/4 still PASS on Linux.
Third and root-cause macOS gap. After the .dylib probe and the timeout helper,
the binaries compiled and linked on macOS but aborted at startup:

  dyld: Library not loaded: /usr/local/BerkeleyDB.5.3/lib/libdb-5.3.dylib

The .dylib carries a baked-in install name, and on macOS the install name takes
precedence over -Wl,-rpath, so the binary looked in an uninstalled location. The
runners never actually needed dynamic linking -- the other CI-wired suites
(test/fuzz) link libdb.a -- so they now PREFER the static library and only fall
back to shared (adding -rpath in that case). This removes the dynamic loader from
the picture instead of fighting it.

Also replaced the hardcoded 'gcc' with "${CC:-cc}": the macOS jobs run clang,
and hardcoding gcc would have been the next failure in this same sequence.

Verified: 4/4 PASS locally and 'ldd hash_unsorted_cmp | grep -c libdb' = 0,
confirming the static link.
@gburd gburd changed the title ci: run the orphaned test/db regression runners ci: run the orphaned test/db regression runners (and make them portable) Sep 7, 2026
@gburd
gburd merged commit 97844e3 into master Sep 7, 2026
48 of 49 checks passed
@gburd
gburd deleted the ci/wire-testdb-runners branch September 7, 2026 03:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant